home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / delivery / deliver.tz / deliver / procs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-07  |  6.7 KB  |  377 lines

  1. /* $Header: procs.c,v 2.6 90/02/23 16:35:59 chip Exp $
  2.  *
  3.  * Process management and misc support.
  4.  *
  5.  * $Log:    procs.c,v $
  6.  * Revision 2.6  90/02/23  16:35:59  chip
  7.  * \Fix problems determining legality of user references.
  8.  * 
  9.  * Revision 2.5  90/02/23  14:16:51  chip
  10.  * Support "#!" in delivery files.
  11.  * Support "user|program" and "user?error" from delivery files.
  12.  * Improve debugging and error message formatting.
  13.  * Rearrange code for clarity.
  14.  * 
  15.  * Revision 2.4  89/11/01  12:19:05  network
  16.  * Delintify.
  17.  * 
  18.  * Revision 2.3  89/11/01  11:51:50  network
  19.  * Add logging.
  20.  * 
  21.  * Revision 2.2  89/09/29  18:18:03  network
  22.  * Save message when delivery file produces no output,
  23.  * unless delivery file output the "DROP" string.
  24.  * Don't recopy temp files for sys and post-user delfiles.
  25.  * 
  26.  * Revision 2.1  89/06/09  12:25:37  network
  27.  * Update RCS revisions.
  28.  * 
  29.  * Revision 1.5  89/06/09  12:23:57  network
  30.  * Baseline for 2.0 release.
  31.  * 
  32.  */
  33.  
  34. #include "deliver.h"
  35. #include <errno.h>
  36. #include <signal.h>
  37.  
  38. /*
  39.  * External data.
  40.  */
  41.  
  42. extern  int     errno;
  43.  
  44. /*
  45.  * Local data.
  46.  */
  47.  
  48. static  int     child_pid = -1;
  49. static  SIGTYPE (*saved_sigpipe)() = SIG_DFL;
  50.  
  51. /*----------------------------------------------------------------------
  52.  * Like popen(), but execute the child in a specific context.
  53.  * Also, the argument list is already a vector.
  54.  */
  55.  
  56. FILE *
  57. ct_fopenv(ct, prog, av, mode)
  58. CONTEXT *ct;
  59. char    *prog;
  60. char    **av;
  61. char    *mode;
  62. {
  63.     FILE    *fp;
  64.     int    fd, m;
  65.  
  66.     if (mode && mode[0] == 'r' && mode[1] == 0)
  67.         m = O_RDONLY;
  68.     else if (mode && mode[0] == 'w' && mode[1] == 0)
  69.         m = O_WRONLY;
  70.     else
  71.         return NULL;
  72.  
  73.     if ((fd = ct_openv(ct, prog, av, m)) == -1)
  74.         return NULL;
  75.  
  76.     if ((fp = fdopen(fd, mode)) == NULL)
  77.         (void) ct_close(fd);
  78.  
  79.     return fp;
  80. }
  81.  
  82. /*----------------------------------------------------------------------
  83.  * Close the stream opened by ct_fopen().
  84.  */
  85.  
  86. ct_fclose(fp)
  87. FILE    *fp;
  88. {
  89.     int    fd;
  90.  
  91.     if (fp)
  92.     {
  93.         fd = dup(fileno(fp));
  94.         (void) fclose(fp);
  95.     }
  96.     else
  97.         fd = -1;
  98.  
  99.     return ct_close(fd);
  100. }
  101.  
  102. /*----------------------------------------------------------------------
  103.  * Like popen(), but execute the child in a specific context.
  104.  * Also, the argument list is already a vector.
  105.  * And return a file descriptor instead of a FILE *.
  106.  */
  107.  
  108. int
  109. ct_openv(ct, prog, av, mode)
  110. CONTEXT *ct;
  111. char    *prog;
  112. char    **av;
  113. int    mode;
  114. {
  115.     char    ch;
  116.     int     child, parent;
  117.     int     pfd[2];
  118.  
  119.     if (!ct || !prog || !av)
  120.         return NULL;
  121.  
  122.     if (mode == O_RDONLY)
  123.         child = 1, parent = 0;
  124.     else if (mode == O_WRONLY)
  125.         child = 0, parent = 1;
  126.     else
  127.     {
  128.         error("in ct_open: invalid mode");
  129.         return -1;
  130.     }
  131.  
  132.     /* We can't have more than one child at a time. */
  133.  
  134.     if (child_pid >= 0)
  135.     {
  136.         error("in ct_open: a process is already open");
  137.         return -1;
  138.     }
  139.  
  140.     /* Make a stab at predicting uid-related failure. */
  141.  
  142.     if (! ok_context(eff_uid, real_uid, real_gid, ct))
  143.     {
  144.         error("in ct_open: no permissions to become %s", ct->ct_name);
  145.         return -1;
  146.     }
  147.  
  148.     /* Pipes?  Like, tubular, fer shur! */
  149.  
  150.     if (pipe(pfd) == -1)
  151.     {
  152.         syserr("can't create a pipe");
  153.         return -1;
  154.     }
  155.  
  156.     /* Generate a debugging message. */
  157.  
  158.     if (verbose)
  159.     {
  160.         int a;
  161.  
  162.         message("%s: spawning", progname);
  163.         for (a = 0; av[a]; ++a)
  164.             message(" %s", av[a]);
  165.         message("\n");
  166.     }
  167.  
  168.     /* Handle the child case */
  169.  
  170.     if (sfork() == 0)
  171.     {
  172.         if (child == 0)
  173.         {
  174.             (void) close(0);
  175.             (void) dup(pfd[0]);     /* ass_u_me 0 */
  176.         }
  177.         else
  178.         {
  179.             (void) close(0);
  180.             if (open("/dev/null", O_RDONLY) != 0)
  181.             {
  182.                 /* This should _never_ happen, but... */
  183.                 syserr("can't open /dev/null");
  184.                 (void) dup(1);  /* ass_u_me 0 */
  185.             }
  186.  
  187.             (void) close(1);
  188.             (void) dup(pfd[1]);     /* ass_u_me 1 */
  189.         }
  190.  
  191.         if (become(ct, TRUE) < 0)
  192.             (void) write(pfd[1], "n", 1);
  193.         else
  194.         {
  195.             int     t;
  196.  
  197.             (void) write(pfd[1], "y", 1);
  198.  
  199.             (void) close(pfd[child]);
  200.             (void) close(pfd[parent]);
  201.             for (t = 0; t < T_MAX; ++t)
  202.                 (void) close(tfd[t]);
  203.             if (log)
  204.                 (void) fclose(log);
  205.             if (errlog)
  206.                 (void) fclose(errlog);
  207.  
  208.             (void) execv(prog, av);
  209.             syserr("can't execute %s", prog);
  210.         }
  211.  
  212.         exit(127);
  213.     }
  214.  
  215.     /* Make sure that a broken pipe won't kill us */
  216.  
  217.     saved_sigpipe = signal(SIGPIPE, SIG_IGN);
  218.  
  219.     /* The child must report "OK" before we continue. */
  220.  
  221.     if ((read(pfd[0], &ch, 1) < 1) || (ch != 'y'))
  222.     {
  223.         (void) close(pfd[0]);
  224.         (void) close(pfd[1]);
  225.         (void) await_child();
  226.         return -1;
  227.     }
  228.  
  229.     (void) close(pfd[child]);
  230.     return pfd[parent];
  231. }
  232.  
  233. /*----------------------------------------------------------------------
  234.  * Close the file descriptor opened by ct_open().
  235.  */
  236.  
  237. ct_close(fd)
  238. int    fd;
  239. {
  240.     if (fd != -1)
  241.         (void) close(fd);
  242.     return await_child();
  243. }
  244.  
  245. /*----------------------------------------------------------------------
  246.  * Assume the identity of the given user.
  247.  */
  248.  
  249. int
  250. become(ct, chd)
  251. CONTEXT *ct;
  252. int     chd;
  253. {
  254.     char    env_path[sizeof(SAFEPATH) + 8];
  255.  
  256.     /*
  257.      * Assume a new identity.
  258.      * Note the importance of doing the setgid() before the setuid().
  259.      */
  260.  
  261.     if (setgid(ct->ct_gid) == -1)
  262.     {
  263.         syserr("can't setgid to %d", ct->ct_gid);
  264.         return -1;
  265.     }
  266.     if (setuid(ct->ct_uid) == -1)
  267.     {
  268.         syserr("can't setgid to %u", ct->ct_uid);
  269.         return -1;
  270.     }
  271.     if (chd && chdir(ct->ct_home) == -1)
  272.     {
  273.         syserr("can't chdir to %s", ct->ct_home);
  274.         return -1;
  275.     }
  276.  
  277.     /* Set up the environment */
  278.  
  279.     env_path[0] = '\0';
  280.     if (ct->ct_uid == 0)
  281.         (void) strcat(env_path, "/etc:");
  282.     (void) strcat(env_path, SAFEPATH);
  283.  
  284.     alloc_env("HOME", ct->ct_home);
  285.     alloc_env("PATH", env_path);
  286.  
  287.     /* I guess it worked. */
  288.  
  289.     return 0;
  290. }
  291.  
  292. /*----------------------------------------------------------------------
  293.  * Safe fork.  If it doesn't work, it exits.
  294.  */
  295.  
  296. int
  297. sfork()
  298. {
  299.     int     tries;
  300.  
  301.     /*
  302.      * A few safety measures.
  303.      */
  304.  
  305.     (void) await_child();
  306.     (void) fflush(stdout);
  307.     (void) fflush(stderr);
  308.     if (log)
  309.         (void) fflush(log);
  310.     if (errlog)
  311.         (void) fflush(errlog);
  312.  
  313.     /*
  314.      * Be patient in waiting for a fork().
  315.      */
  316.  
  317.     for (tries = 0; tries < 10; ++tries)
  318.     {
  319.         if (tries)
  320.             snooze(3);
  321.         if ((child_pid = fork()) >= 0)
  322.             return child_pid;
  323.         if (errno != EAGAIN)
  324.             break;
  325.     }
  326.  
  327.     syserr("can't fork");
  328.     leave(1);
  329.     /* NOTREACHED */
  330. }
  331.  
  332. /*----------------------------------------------------------------------
  333.  * Wait for our child (if any) to exit.
  334.  * Returns child's exit status or -1 if there is a problem.
  335.  */
  336.  
  337. int
  338. await_child()
  339. {
  340.     int     wpid, st;
  341.  
  342.     if (child_pid < 0)
  343.         return -1;
  344.  
  345.     while ((wpid = wait(&st)) >= 0)
  346.     {
  347.         if (wpid == child_pid)
  348.             break;
  349.     }
  350.  
  351.     child_pid = -1;
  352.     if (wpid == -1)
  353.         syserr("waiting for child");
  354.  
  355.     (void) signal(SIGPIPE, saved_sigpipe);
  356.     saved_sigpipe = SIG_DFL;
  357.  
  358.     if (wpid == -1)
  359.         return -1;
  360.  
  361.     if (st & 0xFF)
  362.     {
  363.         error("child process died%s due to signal %d.",
  364.             ((st & 0x80) ? " and dumped core" : ""),
  365.             (st & 0x7F));
  366.         return -1;
  367.     }
  368.  
  369.     if (verbose)
  370.     {
  371.         message("%s: child process exited with status %d.\n",
  372.             progname, (st >> 8) & 0xFF);
  373.     }
  374.  
  375.     return ((st >> 8) & 0xFF);
  376. }
  377.